/*
 * cacheArchivos.c
 *
 *  Created on: 13/11/2011
 *      Author: root
 */

#include<stdint.h>
#include<stdlib.h>
#include<string.h>
#include<stdio.h>
#include"includes/cacheArchivos.h"
#include"includes/variablesGlobales.h"

void crearArchivoCache (char *path,char *nombreArchivo,int32_t nroCluDeArchivo,ptrCacheArchivo *listaCaches){
	int32_t i;
	ptrCacheArchivo nuevoArchivoCache,ptr;
	nuevoArchivoCache=calloc(1,sizeof(cache_t));
	memcpy(nuevoArchivoCache->path,path,strlen(path)+1);
	memcpy(nuevoArchivoCache->nombreArchivo,nombreArchivo,strlen(nombreArchivo)+1);
	nuevoArchivoCache->nroClusterEstaArchivo=nroCluDeArchivo;
	nuevoArchivoCache->tamArchivo=0;
	nuevoArchivoCache->tamBloqueCache=4096;
	nuevoArchivoCache->bloquesSubLista=NULL;
	if(tamCache==0){
		nuevoArchivoCache->cantBloques=0;
	}
	else{
		nuevoArchivoCache->cantBloques=(tamCache/4);
		ptrBloque nuevoBloque,ptrbloque;
		ptrbloque=nuevoArchivoCache->bloquesSubLista;
		for(i=1;i<=nuevoArchivoCache->cantBloques;i++){
			nuevoBloque=calloc(1,sizeof(bloques_t));
			nuevoBloque->nroClusterEnArchivo=0;
			nuevoBloque->nroIngreso=0;
			nuevoBloque->flush=0;
			memset(&nuevoBloque->bloqueInfo,0,4096);
			nuevoBloque->ptrSigBloque=NULL;
			if(i==1){
				nuevoArchivoCache->bloquesSubLista=nuevoBloque;
				ptrbloque=nuevoBloque;
			}
			else{
				ptrbloque->ptrSigBloque=nuevoBloque;
				ptrbloque=nuevoBloque;
			}
		}
	}
	nuevoArchivoCache->ptrSigArchivo=NULL;
	ptr=(*listaCaches);
	if(ptr==NULL){
		(*listaCaches)=nuevoArchivoCache;
	}
	else{
		while(ptr->ptrSigArchivo!=NULL){
			ptr=ptr->ptrSigArchivo;
		}
		ptr->ptrSigArchivo=nuevoArchivoCache;
	}
	return;
}

ptrCacheArchivo buscarArchivoEnCache(char *path,ptrCacheArchivo listaCaches){
	ptrCacheArchivo ptr=NULL;
	ptr=listaCaches;
	while(ptr!=NULL){
		if(strcmp(ptr->path,path)==0){
			return ptr;
		}
		ptr=ptr->ptrSigArchivo;
	}
	return NULL;
}

void cambiarNombreArchivoCache(ptrCacheArchivo *archivoACambiar,char *nuevoNombre){
	int32_t tamNomArchViejo;
	tamNomArchViejo=strlen((*archivoACambiar)->nombreArchivo);
	memcpy((*archivoACambiar)->path + strlen((*archivoACambiar)->path) - tamNomArchViejo,nuevoNombre,strlen(nuevoNombre)+1);
	memset((*archivoACambiar)->nombreArchivo,0,strlen((*archivoACambiar)->nombreArchivo)+1);
	memcpy((*archivoACambiar)->nombreArchivo,nuevoNombre,strlen(nuevoNombre)+1);

	return;
}

void eliminarBloques(ptrBloque *listaBloques){
	ptrBloque ptr;
	if((*listaBloques)==NULL){
		printf("\nYa esta vacio los bloques de info\n");
	}
	else{
		while((*listaBloques)!=NULL){
			ptr=(*listaBloques);
			(*listaBloques)=(*listaBloques)->ptrSigBloque;
			free(ptr);
		}
		printf("\nSe elimino todos los bloques de info");
	}
	return;
}

void eliminarCaches(ptrCacheArchivo *listaCaches){
	ptrCacheArchivo ptr;
	if((*listaCaches)==NULL){
		printf("\nya esta vacia la cache\n");
	}
	else{
		while((*listaCaches)!=NULL){
			ptr=(*listaCaches);
			(*listaCaches)=(*listaCaches)->ptrSigArchivo;
			eliminarBloques(&ptr->bloquesSubLista);
			free(ptr);
		}
		printf("\nSe elimino todas las caches de archivos");
	}
}


/*retorna el bloque en donde se grabo la info, en caso que no se pueda grabar la info en el bloque returna -1 si no tiene habilitado para grabar la info y -2 si le pase un numero de bloque mayor a los que tengo en cache*/
int32_t agregarInfoAbloqueCache(ptrCacheArchivo *archivoCache,int32_t nroClusterEnArchivo,int32_t tamArchivo,char *info){
	(*archivoCache)->tamArchivo=tamArchivo;
	int32_t maximo,minimo,dir;
	int16_t primero=0;
	char * cluster;
	char clusterForRecord[4096];
	ptrBloque ptr,ptrbloques=(*archivoCache)->bloquesSubLista;
	ptr=ptrbloques;
	if(ptrbloques==NULL){
		return -1; /*no tiene bloques para guardar info la cache*/
	}
	else{
		primero=1;
		while(ptr != NULL){
			if(primero){
				maximo=ptr->nroIngreso;
				minimo=ptr->nroIngreso;
				primero=0;
				ptr=ptr->ptrSigBloque;
				continue;
			}
			if(ptr->nroIngreso > maximo){
				maximo=ptr->nroIngreso;
			}
			if(ptr->nroIngreso < minimo){
				minimo=ptr->nroIngreso;
			}
			ptr=ptr->ptrSigBloque;
		}
		ptr=(*archivoCache)->bloquesSubLista;
		while(ptr != NULL){
			if(ptr->nroIngreso != minimo){
				ptr=ptr->ptrSigBloque;
				continue;
			}
			if(ptr->nroIngreso == minimo){
				if(minimo != 0){
					dir=obtenerDirDelCluster(ptr->nroClusterEnArchivo,bootSector);
					memcpy(clusterForRecord,ptr->bloqueInfo,4096);
					grabarCluster(dir,clusterForRecord);
					cluster=leerCluster(dir);
				}
				memcpy(&ptrbloques->bloqueInfo,info,4096);
				ptr->nroClusterEnArchivo=nroClusterEnArchivo;
				maximo++;
				ptr->nroIngreso=maximo;
				ptr->flush=1;
				break;
			}
		}
	}
	return 0;
}

int32_t imprimirBloquesCache(ptrCacheArchivo archivoCache){
	ptrBloque ptrbloque;
	int32_t i,cantBloquesMostrados=0;
	if(archivoCache->cantBloques==0){
		return 0;
	}
	else{
		ptrbloque=archivoCache->bloquesSubLista;
			for(i=1;i<=archivoCache->cantBloques;i++){
				//grabar en el archivo o imprimir en pantalla
				printf("\nContenido de Bloque %d:",i);
				printf("\n%s\n",ptrbloque->bloqueInfo);
				ptrbloque=ptrbloque->ptrSigBloque;
				cantBloquesMostrados++;
			}
		return archivoCache->cantBloques;
	}

}

ptrBloque buscaClusterDeArchivoCache(ptrCacheArchivo cacheArchivo,int32_t nrocluster){
	ptrBloque ptrBloques;
	ptrBloques=cacheArchivo->bloquesSubLista;
	if(ptrBloques==NULL){
		return NULL;
	}
	while(ptrBloques->nroClusterEnArchivo != nrocluster){
		ptrBloques=ptrBloques->ptrSigBloque;
		if(ptrBloques == NULL ){     //Se esta trabando aca , sube y baja!
			break;
		}
	}
	if(ptrBloques != NULL){
		return ptrBloques;
	}
	return NULL;
}

int32_t buscaClusterDeArchivoCacheYCambiaInfo(ptrCacheArchivo *cacheArchivo,int32_t nrocluster,char *info,int32_t tamArchivo){
	ptrBloque ptrBloques;
	ptrBloques=(*cacheArchivo)->bloquesSubLista;
	if(ptrBloques==NULL){
		return -1;
	}
	while(ptrBloques->nroClusterEnArchivo != nrocluster){
		ptrBloques=ptrBloques->ptrSigBloque;
		if(ptrBloques == NULL ){
			break;
		}
	}
	if(ptrBloques != NULL){
		memcpy(&ptrBloques->bloqueInfo,info,4096);
		(*cacheArchivo)->tamArchivo=tamArchivo;
		ptrBloques->flush=1;
		return 0;
	}
	return -1;
}

void flushDelArchivo (ptrCacheArchivo *archivoCache){
	ptrBloque ptrBloqueArchivo;
	int32_t dir;
	char clusterForRecord[4096];
	ptrBloqueArchivo=(*archivoCache)->bloquesSubLista;
	while(ptrBloqueArchivo != NULL){
		if(ptrBloqueArchivo->flush == 1){
			dir=obtenerDirDelCluster(ptrBloqueArchivo->nroClusterEnArchivo,bootSector);
			memcpy(clusterForRecord,ptrBloqueArchivo->bloqueInfo,4096);
			grabarCluster(dir,clusterForRecord);
			ptrBloqueArchivo->flush=0;
		}
		ptrBloqueArchivo=ptrBloqueArchivo->ptrSigBloque;
	}
}















